package com.ayic.garbagerecycle.service.impl;

import com.ayic.garbagerecycle.mapper.TrendMapper;
import com.ayic.garbagerecycle.pojo.*;
import com.ayic.garbagerecycle.service.AnalysisService;
import com.ayic.garbagerecycle.service.StationService;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author AyiC416
 * @ClassName garbagerecycle
 * @date 2025/5/21
 * @Description TODO
 */
@Service
public class AnalysisServiceImpl implements AnalysisService {
    private static final Logger Logger = org.slf4j.LoggerFactory.getLogger(AnalysisServiceImpl.class);

    @Resource
    StationService stationService;
    @Resource
    TrendMapper trendMapper;

    public AnalysisServiceImpl(StationService stationService) {
        this.stationService = stationService;
    }


    //用于将站点根据位置分组的工具方法
    public static Map<String, List<Station>> groupByBuilding(List<Station> stations) {
        // 正则匹配前缀如“一教”、“二教”等
        Pattern pattern = Pattern.compile("^[一二三四五六七八九十]+教");

        return stations.stream()
                .collect(Collectors.groupingBy(station -> {
                    String location = station.getLocation();
                    Matcher matcher = pattern.matcher(location);
                    if (matcher.find()) {
                        return matcher.group();  // 提取到的如“一教”
                    } else {
                        return "其他"; // 未匹配时归入“其他”
                    }
                }));
    }

    public static AnalysisAdvancedData calculateTrend(List<AnalysisData> dailyData) {
        if (dailyData == null || dailyData.size() < 2) {
            return new AnalysisAdvancedData(BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO);
        }

        int n = dailyData.size();

        BigDecimal sumX = BigDecimal.ZERO;
        BigDecimal sumY = BigDecimal.ZERO;
        BigDecimal sumXY = BigDecimal.ZERO;
        BigDecimal sumXX = BigDecimal.ZERO;
        BigDecimal sumYY = BigDecimal.ZERO;

        for (int i = 0; i < n; i++) {
            // x = i + 1
            BigDecimal x = BigDecimal.valueOf(i + 1);

            // y = totalWeight，null时用0
            BigDecimal y = dailyData.get(i).getTotalWeight();
            if (y == null) {
                y = BigDecimal.ZERO;
            }

            sumX = sumX.add(x);
            sumY = sumY.add(y);
            sumXY = sumXY.add(x.multiply(y));
            sumXX = sumXX.add(x.multiply(x));
            sumYY = sumYY.add(y.multiply(y));
        }

        BigDecimal nBig = BigDecimal.valueOf(n);

        // 计算均值 xBar, yBar
        BigDecimal xBar = sumX.divide(nBig, 10, RoundingMode.HALF_UP);
        BigDecimal yBar = sumY.divide(nBig, 10, RoundingMode.HALF_UP);

        // numerator = sumXY - n * xBar * yBar
        BigDecimal numerator = sumXY.subtract(nBig.multiply(xBar).multiply(yBar));

        // denominator = sumXX - n * xBar^2
        BigDecimal denominator = sumXX.subtract(nBig.multiply(xBar.multiply(xBar)));

        if (denominator.compareTo(BigDecimal.ZERO) == 0) {
            // 斜率为0，截距为平均y，R²为0
            return new AnalysisAdvancedData(
                    BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP),
                    yBar.setScale(6, RoundingMode.HALF_UP),
                    BigDecimal.ZERO.setScale(6, RoundingMode.HALF_UP)
            );
        }

        // 斜率 K = numerator / denominator
        BigDecimal k = numerator.divide(denominator, 10, RoundingMode.HALF_UP);

        // 截距 b = yBar - K * xBar
        BigDecimal b = yBar.subtract(k.multiply(xBar));

        // 计算拟合优度 R²
        BigDecimal ssTotal = BigDecimal.ZERO;
        BigDecimal ssResidual = BigDecimal.ZERO;

        for (int i = 0; i < n; i++) {
            BigDecimal y = dailyData.get(i).getTotalWeight();
            if (y == null) {
                y = BigDecimal.ZERO;
            }
            BigDecimal x = BigDecimal.valueOf(i + 1);
            BigDecimal yFit = k.multiply(x).add(b);

            BigDecimal diffTotal = y.subtract(yBar);
            BigDecimal diffResidual = y.subtract(yFit);

            ssTotal = ssTotal.add(diffTotal.multiply(diffTotal));
            ssResidual = ssResidual.add(diffResidual.multiply(diffResidual));
        }

        BigDecimal r2 = BigDecimal.ZERO;
        if (ssTotal.compareTo(BigDecimal.ZERO) != 0) {
            r2 = BigDecimal.ONE.subtract(ssResidual.divide(ssTotal, 10, RoundingMode.HALF_UP));
        }

        return new AnalysisAdvancedData(
                k.setScale(6, RoundingMode.HALF_UP),
                b.setScale(6, RoundingMode.HALF_UP),
                r2.setScale(6, RoundingMode.HALF_UP)
        );
    }

    public static String generateTrendText(AnalysisAdvancedData data, String stationName) {
        if (data == null) return "暂无趋势分析数据。";

        BigDecimal k = data.getK();
        BigDecimal r2 = data.getRSquare();

        StringBuilder result = new StringBuilder();
        result.append("【").append(stationName).append("】站点趋势分析：");

        // 趋势方向
        if (k.compareTo(BigDecimal.valueOf(1.0)) > 0) {
            result.append("当前回收量呈明显上升趋势，");
        } else if (k.compareTo(BigDecimal.valueOf(0.1)) > 0) {
            result.append("当前回收量略有增长，");
        } else if (k.compareTo(BigDecimal.valueOf(-0.1)) >= 0) {
            result.append("当前回收量基本稳定，");
        } else if (k.compareTo(BigDecimal.valueOf(-1.0)) >= 0) {
            result.append("当前回收量略有下降，");
        } else {
            result.append("当前回收量明显下降，");
        }

        // 拟合质量
        if (r2.compareTo(BigDecimal.valueOf(0.7)) >= 0) {
            result.append("趋势较为稳定可靠。");
        } else if (r2.compareTo(BigDecimal.valueOf(0.4)) >= 0) {
            result.append("但趋势存在一定波动。");
        } else {
            result.append("但数据波动较大，趋势不显著。");
        }

        return result.toString();
    }

    // 首先判断是对单独区域分析还是多区域分析
    // 对于区域分析，首先是从数据库中筛选站点，根据站点筛选他们的回收记录，这个可以有一个确定的日期。
    // 然后对每个区域的回收记录进行统计，得到每个区域的回收种类统计,这样就得到了可以进行分析的种类信息.
    // 然后统计每个种类下的回收量，因为没有重量和体积数据，只能采用权重估计将二者模糊化为一个参数
    // 这样通过预设的方法，就可以生成一个简短的报告，或者交给AI让AI来生成再修改。

    @Override
    public Map<String, String> generateReport(Map<String, List<StationInfoLite>> stationMap, List<String> areaIds) {
        Logger.info("当前分析区域列表为：{}", areaIds);

        Map<String, String> allReports = new LinkedHashMap<>();
        List<AreaAnalysisReport> areaReports = new ArrayList<>();

        try {
            for (String areaId : areaIds) {
                List<StationInfoLite> currentAreaStations = stationMap.get(areaId);
                if (currentAreaStations == null || currentAreaStations.isEmpty()) {
                    Logger.warn("区域 {} 没有站点数据，跳过分析。", areaId);
                    continue;
                }

                List<Integer> ids = currentAreaStations.stream()
                        .map(StationInfoLite::getStationId)
                        .toList();

                List<AnalysisData> analysisData = stationService.select30DayGroupedSumsByStationIds(ids);
                Map<Integer, List<AnalysisData>> grouped = analysisData.stream()
                        .collect(Collectors.groupingBy(AnalysisData::getStationId));

                BigDecimal areaTotalWeight = BigDecimal.ZERO;
                int areaTotalRecords = 0;

                BigDecimal totalK = BigDecimal.ZERO;
                BigDecimal totalR = BigDecimal.ZERO;
                int stationCount = 0;

                String maxKStationName = null;
                BigDecimal maxK = null;

                for (StationInfoLite station : currentAreaStations) {
                    List<AnalysisData> dailyData = grouped.getOrDefault(station.getStationId(), Collections.emptyList());
                    dailyData.sort(Comparator.comparing(AnalysisData::getCreatedAt));

                    AnalysisAdvancedData trend = calculateTrend(dailyData);

                    // 累计区域统计
                    if (trend.getK() != null && trend.getRSquare() != null) {
                        totalK = totalK.add(trend.getK());
                        totalR = totalR.add(trend.getRSquare());
                        stationCount++;
                    }

                    if (maxK == null || (trend.getK() != null && trend.getK().compareTo(maxK) > 0)) {
                        maxK = trend.getK();
                        maxKStationName = station.getStationName();
                    }

                    // 累加重量与记录数
                    for (AnalysisData d : dailyData) {
                        if (d.getTotalWeight() != null) {
                            areaTotalWeight = areaTotalWeight.add(d.getTotalWeight());
                        }
                        areaTotalRecords++;
                    }
                }

                // 计算区域平均 K 和 R²
                BigDecimal avgK = stationCount > 0 ? totalK.divide(BigDecimal.valueOf(stationCount), 6, RoundingMode.HALF_UP) : BigDecimal.ZERO;
                BigDecimal avgR = stationCount > 0 ? totalR.divide(BigDecimal.valueOf(stationCount), 6, RoundingMode.HALF_UP) : BigDecimal.ZERO;

                // 构造区域分析报告数据
                AreaAnalysisReport areaTrend = new AreaAnalysisReport();
                areaTrend.setAreaId(areaId);
                areaTrend.setTotalWeight(areaTotalWeight);
                areaTrend.setTotalRecordCount(areaTotalRecords);
                areaTrend.setAverageK(avgK);
                areaTrend.setAverageR(avgR);
                areaTrend.setCreatedAt(LocalDateTime.now());
                areaTrend.setUpdatedAt(LocalDateTime.now());

                // 构造区域描述文本
                StringBuilder areaSummary = new StringBuilder();
                areaSummary.append(String.format("区域 %s 在过去30天内共回收总重量：%s ，记录数：%d 条；\n",
                        areaId, areaTotalWeight.toPlainString(), areaTotalRecords));
                areaSummary.append(String.format("区域内站点平均每日回收增长率为 %s，平均拟合优度 R² 为 %s；\n",
                        avgK.toPlainString(), avgR.toPlainString()));
                if (maxKStationName != null && maxK != null) {
                    areaSummary.append(String.format("增长最快的站点为【%s】，其增长率为 %s。\n",
                            maxKStationName, maxK.toPlainString()));
                }

                String areaSummaryText = areaSummary.toString().replace("\n", " ");
                allReports.put("区域汇总：" + areaId, areaSummaryText);
                Logger.debug("区域 {} 汇总：{}", areaId, areaSummaryText);

                // 将区域分析报告添加到列表中
                areaReports.add(areaTrend);
            }

            // 生成区域间比较报告
            if (areaReports.size() > 1) {
                StringBuilder comparisonSummary = new StringBuilder();
                comparisonSummary.append("\n\n【区域间比较分析】\n");

                // 按总回收记录数（频率）排序
                areaReports.sort(Comparator.comparing(AreaAnalysisReport::getTotalRecordCount).reversed());
                comparisonSummary.append(String.format("回收频率最高的区域是【%s】（记录数：%d 条），最低的区域是【%s】（记录数：%d 条）。\n",
                        areaReports.get(0).getAreaId(), areaReports.get(0).getTotalRecordCount(),
                        areaReports.get(areaReports.size() - 1).getAreaId(), areaReports.get(areaReports.size() - 1).getTotalRecordCount()));

                // 按总回收重量（价值）排序
                areaReports.sort(Comparator.comparing(AreaAnalysisReport::getTotalWeight).reversed());
                comparisonSummary.append(String.format("回收价值最高的区域是【%s】（总重量：%s），最低的区域是【%s】（总重量：%s）。\n",
                        areaReports.get(0).getAreaId(), areaReports.get(0).getTotalWeight().toPlainString(),
                        areaReports.get(areaReports.size() - 1).getAreaId(), areaReports.get(areaReports.size() - 1).getTotalWeight().toPlainString()));

                // 根据频率和价值给出建议
                comparisonSummary.append("\n【建议】\n");
                AreaAnalysisReport highestFreq = areaReports.stream().max(Comparator.comparing(AreaAnalysisReport::getTotalRecordCount)).orElse(null);
                AreaAnalysisReport lowestFreq = areaReports.stream().min(Comparator.comparing(AreaAnalysisReport::getTotalRecordCount)).orElse(null);
                AreaAnalysisReport highestValue = areaReports.stream().max(Comparator.comparing(AreaAnalysisReport::getTotalWeight)).orElse(null);
                AreaAnalysisReport lowestValue = areaReports.stream().min(Comparator.comparing(AreaAnalysisReport::getTotalWeight)).orElse(null);

                if (highestFreq != null) {
                    comparisonSummary.append(String.format("对于回收频率较高的区域如【%s】，可以考虑增加回收频次或投放更多回收设施，以应对较高的回收需求。\n", highestFreq.getAreaId()));
                }
                if (lowestFreq != null) {
                    comparisonSummary.append(String.format("对于回收频率较低的区域如【%s】，可以分析原因，例如宣传不足或设施不便，并采取相应措施提高居民参与度。\n", lowestFreq.getAreaId()));
                }
                if (highestValue != null) {
                    comparisonSummary.append(String.format("对于回收价值较高的区域如【%s】，可以重点关注高价值回收物的分类和收集，提高回收效率和收益。\n", highestValue.getAreaId()));
                }
                if (lowestValue != null) {
                    comparisonSummary.append(String.format("对于回收价值较低的区域如【%s】，可以研究是否是投放习惯或回收物种类导致，考虑调整宣传策略或引导居民投放高价值回收物。\n", lowestValue.getAreaId()));
                }

                allReports.put("区域间比较", comparisonSummary.toString().replace("\n", " "));
                Logger.debug("区域间比较：{}", comparisonSummary.toString().replace("\n", " "));
            }
        } catch (Exception e) {
            throw new RuntimeException("区域分析失败", e);
        }
        return allReports;
    }

    @Override
    public String generateStationReport(Integer stationId) {

        Station station = stationService.getStationById(stationId);

        BigDecimal currentCapacity = BigDecimal.valueOf(station.getCurrentCapacity());
        BigDecimal capacity = BigDecimal.valueOf(station.getCapacity());
        BigDecimal tempK = new BigDecimal("0");

        try {
            List<AnalysisData> analysisData = stationService.select30DayGroupedSumsByStationId(stationId);
            Map<Integer, List<AnalysisData>> grouped = analysisData.stream()
                    .collect(Collectors.groupingBy(AnalysisData::getStationId));

            // 临时保存站点趋势文本，稍后统一合并进区域报告中
            List<String> stationTrendTexts = new ArrayList<>();

            AnalysisAdvancedData trend = calculateTrend(analysisData);

            // 单个站点趋势描述
            String trendDescription = generateTrendText(trend, station.getStationName());
            stationTrendTexts.add("【" + station.getStationName() + "】" + trendDescription);

            WasteTrend wasteTrend = new WasteTrend();
            wasteTrend.setK(trend.getK());
            tempK = trend.getK();
            wasteTrend.setR(trend.getRSquare());
            wasteTrend.setStationId(station.getStationId());
            wasteTrend.setTrendDescription(trendDescription);
            wasteTrend.setCreatedAt(LocalDateTime.now());
            wasteTrend.setUpdatedAt(LocalDateTime.now());


            trendMapper.insertWasteTrend(wasteTrend);
            // 单个站点趋势分析已存入数据库

        } catch (Exception e) {
            throw new RuntimeException("区域分析失败", e);
        }
        String tempReport = trendMapper.getNewestReport(stationId);
        int day = 0;
        if(tempK.compareTo(BigDecimal.ZERO) > 0)
        {
            while (currentCapacity.compareTo(capacity) <= 0) {
                day++;
                // current = current * (1 + tempK)
                currentCapacity = currentCapacity.multiply(BigDecimal.ONE.add(tempK)).setScale(2, RoundingMode.HALF_UP);
            }
            return tempReport  + "当前站点的日增长率为" + tempK.toPlainString() + ",预计"+ day+ "天后将满载。";
        }
        else if (tempK.compareTo(BigDecimal.ZERO) < 0){
            return tempReport + "当前站点的日增长率为" + tempK.toPlainString() + ",当前站点的日回收量正下降。";
        }
            return tempReport;
    }


}
